package com.vains.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vains.entity.OauthPermission;
import com.vains.entity.customer.OAuthPermissionCustomer;
import com.vains.mapper.OauthPermissionMapper;
import com.vains.service.IOauthPermissionService;
import com.vains.utils.SecurityContextUtils;
import com.vains.utils.SpringContextUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源表 服务实现类
 * </p>
 *
 * @author vains
 * @since 2020-06-08
 */
@Slf4j
@Service
@AllArgsConstructor
public class OauthPermissionServiceImpl extends ServiceImpl<OauthPermissionMapper, OauthPermission> implements IOauthPermissionService {

    /*@Value("${jwt-token.secret-key}")
    private String secretKey;

    private final RedisUtils<List<OauthPermission>> redisUtils;

    private final RedisUtils<OauthUser> redisUserUtils;

    public OauthPermissionServiceImpl(RedisUtils<List<OauthPermission>> redisUtils, RedisUtils<OauthUser> redisUserUtils) {
        this.redisUtils = redisUtils;
        this.redisUserUtils = redisUserUtils;
    }*/

    private final ResourceServerTokenServices resourceServerTokenServices;

    @Override
    public List<OauthPermission> getMenus() {
        QueryWrapper<OauthPermission> wrapper = new QueryWrapper<>();
        wrapper.eq("permission_deleted", false);
        wrapper.eq("permission_type", 0);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<OauthPermission> getPermissions(Page<OauthPermission> page) {
        QueryWrapper<OauthPermission> wrapper = new QueryWrapper<>();
        wrapper.eq("permission_deleted", false);
        if (page != null) {
            Page<OauthPermission> permissionPage = baseMapper.selectPage(page, wrapper);
            return permissionPage.getRecords();
        }
        return baseMapper.selectList(wrapper);
    }

    private List<OauthPermission> getPermissions() {
        QueryWrapper<OauthPermission> wrapper = new QueryWrapper<>();
        // 未删除的
        wrapper.eq("permission_deleted", false);
        // 不是导航栏的
        wrapper.ne("permission_type", 0);
        return baseMapper.selectList(wrapper);
    }

    /**
     * 判断是否有权限
     * @return 返回判断
     */
    @Override
    public boolean hasPermission() {
        HttpServletRequest request = SpringContextUtils.getCurrentRequest();
        return hasPermission(request.getRequestURI());
        /*// 获取token, token不存在说明未登录
        String token = SpringContextUtils.getCurrentToken();
        // 从token中获取用户ID
        Integer userId = JwtUtils.getUserId(token, secretKey);
        // 根据用户ID取出redis上边用户的信息
        OauthUser oauthUser = redisUserUtils.get(RedisKeyConstant.OAUTH_USER_INFO_PREV + userId);
        for (GrantedAuthority authorityDto : oauthUser.getAuthorities()) {
            if (new AntPathRequestMatcher(authorityDto.getAuthority()).matches(request) || request.getRequestURI().startsWith(authorityDto.getAuthority())) {
                return true;
            }
        }
        throw new CustomException(ResultEnum.NO_PERMISSION.getMessage());*/
    }

    @Override
    public List<OAuthPermissionCustomer> getAllPermissions(Page<OauthPermission> page) {
        if (page == null) {
            return baseMapper.getAllPermissions(null);
        }
        return baseMapper.getAllPermissions(page);
    }

    @Override
    public boolean checkPermissionName(String name) {
        QueryWrapper<OauthPermission> wrapper = new QueryWrapper<>();
        wrapper.eq("permission_name", name);
        wrapper.eq("permission_deleted", false);
        // 如果是空的,代表可以添加,否则不符合,不能添加
        return CollectionUtils.isEmpty(baseMapper.selectList(wrapper));
    }

    @Override
    public boolean checkPermissionUrl(String url) {
        QueryWrapper<OauthPermission> wrapper = new QueryWrapper<>();
        wrapper.eq("permission_url", url);
        wrapper.eq("permission_deleted", false);
        // 如果是空的,代表可以添加,否则不符合,不能添加
        return CollectionUtils.isEmpty(baseMapper.selectList(wrapper));
    }

    @Override
    public boolean hasPermission(String url) {
        Assert.hasLength(url, "判断权限的地址不能为空!");
        // 去除网关代理的前缀
        String[] uris = url.split("/");
        StringBuilder serviceUrl = new StringBuilder();
        // 如果根据 / 截取的字符串长度大于等于2则代表 访问的是接口或者通过网关访问
        if (uris.length >= 2) {
            uris[1] = "";
            for (String s : uris) {
                // 如果s是空的,则跳过, 不拼接url
                if (org.springframework.util.StringUtils.isEmpty(s)) {
                    continue;
                }
                serviceUrl.append("/").append(s);
            }
        } else {
            serviceUrl.append(url);
        }
        String requestPath = serviceUrl.toString();
        List<String> resources = new ArrayList<>();
        loadResourceDefine(resources);

        if (CollectionUtils.isEmpty(resources)) {
            return true;
        }

        // 找出数据库中 以请求地址开头的
        List<String> matchRequestUri = resources.stream().filter(e -> !StringUtils.isEmpty(e) && requestPath.startsWith(e)).collect(Collectors.toList());

        // 如果数据库中不存在请求地址 并且没有契合请求地址开头的， 直接放行
        if (!resources.contains(requestPath) && CollectionUtils.isEmpty(matchRequestUri)) {
            return true;
        }

        OAuth2Authentication authentication = SecurityContextUtils.getAuthenticationByToken(resourceServerTokenServices);
        if (authentication == null) {
            // 根据请求中的token获取认证信息失败
            return false;
        }
        //OauthUser principal = (OauthUser) authentication.getPrincipal();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (GrantedAuthority authorityDto : authorities) {
            if (authorityDto.getAuthority().contains(requestPath) || requestPath.startsWith(authorityDto.getAuthority())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 加载权限表中所有权限
     */
    private void loadResourceDefine(List<String> resources) {
        // 加载所有资源
        List<OauthPermission> permissions = this.getPermissions();

        if (CollectionUtils.isEmpty(permissions)) {
            return;
        }
        // 使用stream提取出权限信息中的url
        List<String> permissionList = permissions.stream().map(OauthPermission::getPermissionUrl).collect(Collectors.toList());
        // 放入参数中
        resources.addAll(permissionList);
    }

}
